﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using BrickBreaker.Core;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

namespace BrickBreaker.Core
{
    public struct PowerUp
    {

        PowerType powerType;
        PowerUpObject gameObject;

        public PowerType PowerUpType
        {
            get { return this.powerType; }
            set { this.powerType = value; }
        }
        public PowerUpObject GameObject
        {
            get { return this.gameObject; }
            set { this.gameObject = value; }
        }
    };

    public class BBPowerupManager
    {
        #region Data Members
        //
        private List<PowerType> availablePowerUps;
        private List<PowerType> unavailablePowerUps;

        private List<BBPowerup> powerups;

        private BBPowerup deadPowerup;
        private BBPowerup caughtPowerup;

        private PowerType lastChosenType;
        
        //private int count;
        private int index;
        private int seed;
        private int powerupWeight;
        
        //
        #endregion



        #region Private Methods
        //
        /// <summary>
        /// Initializes the list with all types of powerups
        /// </summary>
        /// <param name="powerUpMin">The least amount of powerup types (typically 0 - None).</param>
        /// <param name="powerUpMax">The max amount of powerup types (PowerType.Count)</param>
        private void initPowerupLists(int powerUpMin, int powerUpMax)
        {
            availablePowerUps = new List<PowerType>();
            unavailablePowerUps = new List<PowerType>();
            powerups = new List<BBPowerup>();

            // initialize all powerups as unavailable
            for (int i = powerUpMin; i <= powerUpMax; i++)
            {
                unavailablePowerUps.Add((PowerType)i);
            }

            UnlockNewPowerUp(PowerType.NONE);
        }

        /// <summary>
        /// Creates a new powerup of the specified type
        /// </summary>
        /// <param name="type">The type of power up being unlocked.</param>
        private BBPowerup CreatePowerUp(PowerType type)
        {
            BBPowerup powerup = new BBPowerup(Vector2.Zero);

            powerup.Type = type;
            powerup.Name = type.ToString();
            powerup.Active = true;
            powerup.SetTexture(type);//powerup.Name);

            return powerup;
        }

        /// <summary>
        /// Retrieves a powerup from a list of unavaiilable powerups
        /// </summary>
        private PowerType GetUnavailablePowerUp()
        {
            // once all powerup textures are in, check against 0
            if (unavailablePowerUps.Count > 0)
            {
                Random rand = new Random();

                int num = rand.Next(0, unavailablePowerUps.Count);

                // until textures are made for these types, skip them
                //while ((unavailablePowerUps[num] == PowerType.MULTIPLIER_2X) || (unavailablePowerUps[num] == PowerType.MULTIPLIER_4X))
                //{
                num = rand.Next(0, unavailablePowerUps.Count);
                //}

                return unavailablePowerUps[num];//unavailablePowerUps[num];
            }
            else
            {
                return PowerType.NONE;
            }
        }

        /// <summary>
        /// Checks to see if the given power up should be dead or not.
        /// </summary>
        /// <pparam name="powerup">The power up being checked against.</pparam>
        private bool isPowerupDead(BBPowerup powerup)
        {
            return (powerup.Position.Y + powerup.Size.Y > BBGlobalConfig.getWindowHeight());
        }
        //
        #endregion


        #region Object Construction
        //
        /// <summary>
        /// Creates a manager which controls all powerups in the world.
        /// </summary>
        public BBPowerupManager()
        {
            int numOfPowerUps = Enum.GetValues(typeof(PowerType)).Length - 1;
            initPowerupLists((int)PowerType.NONE, numOfPowerUps);

            deadPowerup = null;
            caughtPowerup = null;
            
            seed = 0;
            
            Random rand = new Random(seed);

            // initially set a weight for probability (1 - 3)
            powerupWeight = rand.Next(1, 4);
        }
        //
        #endregion


        #region Public Methods
        //
        /// <summary>
        /// Retrieves a powerup from a list of available powerups
        /// </summary>
        public BBPowerup GetAvailablePowerUp()
        {
            // increment the index to get closer to probability weight.
            index++;

            // increment the seed so random can be truely random.
            seed++;

            if (availablePowerUps.Count > 0)
            {
                Random rand = new Random(seed);
                int num = 0;

                // the weight might change after a powerup drops.
                // if time to grab a powerup
                if (index > powerupWeight)
                {
                    // retrieve a specific type of powerup
                    num = rand.Next(1, availablePowerUps.Count);

                    // make sure it doesn't choose the same type constantly
                    if (availablePowerUps[num] == lastChosenType)
                    {
                        // loop until the type chosen is not the same as the last one.
                        while (availablePowerUps[num] == lastChosenType)
                        {
                            // retrieve a specific type of powerup
                            num = rand.Next(1, availablePowerUps.Count);
                        }
                    }

                    // assigns the type as the last type so it won't be chosen repeatedly.
                    lastChosenType = availablePowerUps[num];

                    // reset the index
                    index = 0;

                    // choose a new weight ( 1 - 3)
                    powerupWeight = rand.Next(1, 4);
                }
                else
                {
                    // set num to 0 so that the powerup will be of type NONE
                    num = 0;
                }

                if (availablePowerUps[num] != PowerType.NONE)
                {
                    // create the powerup
                    BBPowerup powerup = CreatePowerUp(availablePowerUps[num]);

                    return powerup;
                }
                else { return null; }
            }
            else { return null; }
        }

        /// <summary>
        /// Unlocks a new power up from the unavailable list to be available for use.
        /// This function returns a specific type of power up.
        /// </summary>
        /// <param name="type">The type of power up being unlocked.</param>
        public void UnlockNewPowerUp(PowerType type)
        {
            for (int i = 0; i < unavailablePowerUps.Count; i++)
            {
                if (unavailablePowerUps[i] == type)
                {
                    availablePowerUps.Add(type);
                    unavailablePowerUps.Remove(type);
                    break;
                }
            }
        }

        /// <summary>
        /// Unlocks a new power up from the unavailable list to be available for use.
        /// This function returns a random type of power up.
        /// </summary>
        public void UnlockNewPowerUp()
        {
            PowerType type = GetUnavailablePowerUp();

            for (int i = 0; i < unavailablePowerUps.Count; i++)
            {
                if (unavailablePowerUps[i] == type)
                {
                    availablePowerUps.Add(type);
                    unavailablePowerUps.Remove(type);
                    break;
                }
            }
        }

        /// <summary>
        /// Responsible for updating all the powerups in the world.
        /// </summary>
        public void Update()
        {
            if (powerups.Count > 0)
            {
                foreach (BBPowerup powerUp in powerups)
                {
                    powerUp.Update();

                    if (isPowerupDead(powerUp)) { deadPowerup = powerUp; }
                    else { deadPowerup = null; }
                }

                if (deadPowerup != null) { DestroyPowerUp(deadPowerup); }

            }
        }

        /// <summary>
        /// Responsible for drawing all powerups in the world.
        /// </summary>
        /// <param name="spriteBatch">Your spritebatch.  Make sure you have already called begin().</param>
        public void Draw(SpriteBatch spriteBatch)
        {
            if (powerups.Count > 0)
            {
                foreach (BBPowerup powerUp in powerups)
                {
                    powerUp.Draw(spriteBatch);
                }
            }

            //spriteBatch.DrawString(BBGlobalConfig.font, powerupWeight.ToString(), new Vector2(700f, 500f), Color.White);

            #region DEBUG

            if (BBGlobalConfig.DisplayDebug == true)
            {
                int count = 0;

                // list all available powerups
                foreach (PowerType type in availablePowerUps)
                {
                    count += 25;
                    spriteBatch.DrawString(BBGlobalConfig.font, type.ToString(), new Vector2(700, count), Color.White);
                }
            }

            #endregion
        }

        /// <summary>
        /// Adds the given powerup to the managers control.
        /// </summary>
        /// <pparam name="powerup">The power up which is being added to the manager.</pparam>
        public void AddPowerUp(BBPowerup powerup)
        {
            powerups.Add(powerup);
        }

        /// <summary>
        /// Releases the given powerup from the managers control and destroys it.
        /// </summary>
        /// <pparam name="powerup">The power up being destroyed.</pparam>
        private void DestroyPowerUp(BBPowerup powerup)
        {
            powerups.Remove(powerup);
        }

        public bool caughtByPaddle(BBPaddle paddle)
        {
            bool isCaught = false;

            foreach (BBPowerup powerup in powerups)
            {
                if (powerup.Intersects(paddle.getRectBounds()))
                {
                    if (paddle.hasCollided(powerup))
                    {
                        this.caughtPowerup = powerup;
                        DestroyPowerUp(powerup);
                        isCaught = true;
                        break;
                    }
                }
            }

            if (!isCaught)
            {
                caughtPowerup = null;
            }

            return isCaught;
        }

        public PowerUp getCaughtPowerup()
        {
            PowerUp power = new PowerUp();

            switch (caughtPowerup.Type)
            {
                case PowerType.SHORT:
                    power.GameObject = PowerUpObject.PADDLE;
                    power.PowerUpType = PowerType.SHORT;
                    break;
                case PowerType.NORMAL:
                    power.GameObject = PowerUpObject.PADDLE;
                    power.PowerUpType = PowerType.NORMAL;
                    break;
                case PowerType.LONG:
                    power.GameObject = PowerUpObject.PADDLE;
                    power.PowerUpType = PowerType.LONG;
                    break;
                case PowerType.SINGLE_SHOOT:
                    power.GameObject = PowerUpObject.PADDLE;
                    power.PowerUpType = PowerType.SINGLE_SHOOT;
                    break;
                case PowerType.DOUBLE_SHOOT:
                    power.GameObject = PowerUpObject.PADDLE;
                    power.PowerUpType = PowerType.DOUBLE_SHOOT;
                    break;
                case PowerType.STICKY:
                    power.GameObject = PowerUpObject.PADDLE;
                    power.PowerUpType = PowerType.STICKY;
                    break;
                case PowerType.FAST:
                    power.GameObject = PowerUpObject.BALL;
                    power.PowerUpType = PowerType.FAST;
                    break;
                case PowerType.SLOW:
                    power.GameObject = PowerUpObject.BALL;
                    power.PowerUpType = PowerType.SLOW;
                    break;
                case PowerType.SPLIT:
                    power.GameObject = PowerUpObject.BALL;
                    power.PowerUpType = PowerType.SPLIT;
                    break;
                case PowerType.BOMB:
                    power.GameObject = PowerUpObject.BALL;
                    power.PowerUpType = PowerType.BOMB;
                    break;
                case PowerType.MULTIPLIER_2X:
                    power.GameObject = PowerUpObject.SCORE;
                    power.PowerUpType = PowerType.MULTIPLIER_2X;
                    break;
                case PowerType.MULTIPLIER_4X:
                    power.GameObject = PowerUpObject.SCORE;
                    power.PowerUpType = PowerType.MULTIPLIER_4X;
                    break;
                default:
                    power.GameObject = PowerUpObject.NONE;
                    power.PowerUpType = PowerType.NONE;
                    break;
            }

            return power;
            ////if (caughtPowerup.Type == PowerType.NONE) 
            ////{ 
            ////    return PowerType.NONE; 
            ////}
            ////else { return caughtPowerup.Type; }
        }

        public void Reset()
        {
            powerups.Clear();
        }
        //
        #endregion
    }
}
